home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / BBS-Archive / Dev / GNU-TILE-FORTH.lha / src / io.c < prev    next >
C/C++ Source or Header  |  1992-05-19  |  10KB  |  416 lines

  1. /*
  2.   C BASED FORTH-83 MULTI-TASKING IO MANAGEMENT
  3.  
  4.   Copyright (C) 1988-1990 by Mikael Patel
  5.  
  6.   Computer Aided Design Laboratory (CADLAB)
  7.   Department of Computer and Information Science
  8.   Linkoping University
  9.   S-581 83 LINKOPING
  10.   SWEDEN
  11.  
  12.   Email: mip@ida.liu.se
  13.   
  14.   Started on: 30 June 1988
  15.  
  16.   Last updated on: 26 June 1990
  17.  
  18.   Dependencies:
  19.        (cc) fcntl.h, errno.h, kernel.h, error.h, memory.h and io.h
  20.  
  21.   Description:
  22.        Handles low level access to Operating System to allow asynchronous
  23.        input and multi-tasking of Forth level processes while waiting for
  24.        buffer filling. File names are saved so that files are not reloaded. 
  25.   
  26.   Copying:
  27.        This program is free software; you can redistribute it and/or modify
  28.        it under the terms of the GNU General Public License as published by
  29.        the Free Software Foundation; either version 1, or (at your option)
  30.        any later version.
  31.  
  32.        This program is distributed in the hope that it will be useful,
  33.        but WITHOUT ANY WARRANTY; without even the implied warranty of
  34.        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  35.        GNU General Public License for more details.
  36.  
  37.        You should have received a copy of the GNU General Public License
  38.        along with this program; see the file COPYING.  If not, write to
  39.        the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  40.  
  41. */
  42.  
  43.  
  44. #include <fcntl.h>
  45. #include <errno.h>
  46. #include "kernel.h"
  47. #include "error.h"
  48. #include "memory.h"
  49. #include "io.h"
  50.  
  51.  
  52. /* EXTERNAL DEFINED IO DISPATCH ROUTINE, ENVIRONMENT ACCESS AND ERROR CODE */
  53.  
  54. extern VOID io_dispatch();
  55. extern CSTR getenv();
  56. extern INT  errno;
  57.  
  58.  
  59. /* MAXIMUM FILE AND PATH NAME STRING SIZES */
  60.  
  61. #define FILENAMESIZE 128
  62. #define PATHNAMESIZE 128
  63.  
  64.  
  65. /* INFILE BUFFERS STACK AND STACK POINTER */
  66.  
  67. #define INFSTACKSIZE 32
  68.  
  69. INFILE_BUFFER io_infstack[INFSTACKSIZE];
  70. INT io_infsp = -1;
  71.  
  72.  
  73. /* OUTFILE AND ERROR FILE VARIABLES */
  74.  
  75. FILE *io_outf;
  76. FILE *io_errf;
  77.  
  78.  
  79. /* STACK OF NAMES OF LOADED FILE */
  80.  
  81. #define INFILESSIZE 64
  82.  
  83. static CSTR infiles[INFILESSIZE];
  84. static INT infsp = -1;
  85.  
  86.  
  87. /* STACK OF FILE SEARCH PATHS */
  88.  
  89. #define PATHSSIZE 32
  90.  
  91. static CSTR paths[PATHSSIZE];
  92. static INT psp = -1;
  93.  
  94.  
  95. /* IO MANAGEMENT DEFINITONS */
  96.  
  97. INT io_path(pname, pos)
  98.     CSTR pname;            /* Pointer to path name */
  99.     INT pos;            /* Position to append */
  100. {
  101.     CHAR pathname[PATHNAMESIZE];    
  102.     INT plen = strlen(pname);
  103.     INT i;
  104.  
  105.     /* Check for null path. Dont add these */
  106.     if (plen == 0) return IO_NO_ERROR;
  107.  
  108.     /* Check if the path name is an environment variable */
  109.     if (pname[0] == '$') {
  110.  
  111.     /* Fetch the environment variables value */
  112.     char *paths = (char *) getenv((char *) pname + 1);
  113.  
  114.     /* If paths are available recursivly add them to the path list */
  115.     if (paths) {
  116.         while (*paths) {
  117.         char *p = pathname;
  118.  
  119.         /* Parse list of paths; directories seperated by colon */
  120.         while (*paths && *paths != ':') *p++ = *paths++;
  121.         *p++ = '\0'; 
  122.  
  123.         /* Append recursively */
  124.         (VOID) io_path(pathname, pos);
  125.  
  126.         /* Access next path if available */
  127.         if (*paths) paths++;
  128.         }
  129.         return IO_NO_ERROR;
  130.     }
  131.     else
  132.         return IO_UNKNOWN_PATH;
  133.     }
  134.  
  135.     /* Check that the last character is a slash if not add it */
  136.     if (pname[plen - 1] != DIRSEPCHAR && pname[plen - 1] != ':') {
  137.     pname[plen++] = DIRSEPCHAR;
  138.     pname[plen] = '\0';
  139.     }
  140.  
  141.  
  142.     /* Check if the path has already been defined */
  143.     for (i = 0; i <= psp; i++)
  144.     if (STREQ(paths[i], pname)) return IO_PATH_DEFINED;
  145.     
  146.     /* Check if space is available on path stack */
  147.     if (psp + 1 == PATHSSIZE) return IO_TOO_MANY_PATHS;
  148.  
  149.     /* Make space for the new path */
  150.     psp = psp + 1;
  151.     
  152.     /* Check where the path should be appended */
  153.     if (pos == IO_PATH_FIRST) {
  154.     for (i = psp; i > 0; i--) paths[i] = paths[i - 1];
  155.     pos = 0;
  156.     }
  157.     else pos = psp;
  158.  
  159.     /* Add path string att position given */
  160.     paths[pos] = strcpy((char *) malloc((unsigned) plen + 1), pname);
  161.  
  162.     return IO_NO_ERROR;
  163. }
  164.  
  165. VOID io_flush()
  166. {
  167.     /* Flush any waiting output */
  168.     (VOID) fflush(stdout);    
  169.  
  170.     /* Close all open files if not end of input stream */
  171.     if (io_not_eof()) {
  172.  
  173.     /* Close all files but lowest */
  174.     while (io_infsp > 0) (VOID) close(io_infstack[io_infsp--] -> fd);
  175.  
  176.     /* Close lowest file on file stack if not tty */
  177.     if (!isatty(io_infstack[io_infsp] -> fd))
  178.         (VOID) close(io_infstack[io_infsp--] -> fd);
  179.     }
  180. }
  181.  
  182. INT io_infile(fname)
  183.     CSTR fname;            /* Pointer to file name to open as input */
  184. {
  185.     CHAR filename[FILENAMESIZE];
  186.     INT i, j;
  187.     INT fd;
  188.     
  189.     /* Check for standard input as source */
  190.     if (fname == STDIN) {
  191.  
  192.     /* Check if space is available on file stack */
  193.     if (io_infsp + 1 == INFSTACKSIZE) return IO_TOO_MANY_FILES;
  194.  
  195.     /* Push standard input as source onto the file buffer stack */
  196.     io_infsp = io_infsp + 1;
  197.     io_infstack[io_infsp] -> fd = STDIN;
  198.     io_infstack[io_infsp] -> bufp = 0;
  199.     io_infstack[io_infsp] -> cc = 0;
  200.     io_infstack[io_infsp] -> fn = NIL;
  201.     io_infstack[io_infsp] -> ln = 1;
  202.     return IO_NO_ERROR;
  203.     }
  204.  
  205.     /* Expand the file name using the path stack and try opening the file */
  206.     for (i = 0; i <= psp; i++) {
  207.  
  208.     /* Build the new file name using a path */
  209.     (VOID) strcpy(filename, paths[i]);
  210.     (VOID) strcpy(filename + strlen(paths[i]), fname);
  211.  
  212.     /* Check if this file has already been loaded */
  213.     for (j = 0; j <= infsp; j++)
  214.         if (STREQ(infiles[j], filename)) return IO_FILE_INCLUDED;
  215.  
  216.     /* Try opening the file */
  217.     fd = open(filename, O_RDONLY);
  218.  
  219.     /* If no errors then save the file name and return file descriptor */
  220.     if (fd != -1) {
  221.  
  222.         /* Check if space is available on file stack */
  223.         if (io_infsp + 1 == INFSTACKSIZE) return IO_TOO_MANY_FILES;
  224.  
  225.         /* Push file onto the file buffer stack and use it as source */
  226.         infsp = infsp + 1;
  227.         infiles[infsp] = strcpy((char *) malloc((unsigned) strlen(filename) + 1), filename);
  228.         io_infstack[++io_infsp] -> fd = fd;
  229.         io_infstack[io_infsp] -> bufp = 0;
  230.         io_infstack[io_infsp] -> cc = 0;
  231.         io_infstack[io_infsp] -> fn = infiles[infsp];
  232.         io_infstack[io_infsp] -> ln = 1;
  233.         return fd;
  234.     }
  235.     }
  236.  
  237.     /* The file was not available so return error */
  238.     return IO_UNKNOWN_FILE;
  239. }
  240.  
  241.  
  242. INT io_fillbuf()
  243. {
  244.     BOOL nonblocking;
  245.  
  246.     /* Check io consistency and foreground task input only */
  247.     if (io_eof() || tp != foreground) error_fatal(0);
  248.     
  249.     /* Flush any waiting output if filling buffer from a terminal */
  250.     if (isatty(io_infstack[io_infsp] -> fd)) (VOID) fflush(stdout);
  251.  
  252.     /* Check for multi-tasking input operation */
  253.     if (tp != ((TASK) tp -> queue.succ)) {
  254.     (VOID) fcntl(io_infstack[io_infsp] -> fd, F_SETFL, FNDELAY); 
  255.     tp -> status = IOWAITING;
  256.     nonblocking = TRUE;
  257.     }
  258.     else
  259.     nonblocking = FALSE;
  260.     
  261.     /* Allow multi-tasking during waiting for input */
  262.     for (;;) {
  263.  
  264.     /* Try reading a block from the current input stream */
  265.     if ((io_infstack[io_infsp] -> cc = read(io_infstack[io_infsp] -> fd,
  266.                         io_infstack[io_infsp] -> buf,
  267.                         BUFSIZE)) > 0) {
  268.  
  269.         /* Restore to non-blocking input from file and foreground */
  270.         if (nonblocking) {
  271.         (VOID) fcntl(io_infstack[io_infsp] -> fd, F_SETFL, 0);
  272.         spush(foreground, TASK);
  273.         doresume();
  274.         tp -> status = RUNNING;
  275.         }
  276.  
  277.         /* Initiate the buffer pointer and return the first character */
  278.         io_infstack[io_infsp] -> bufp = 0;
  279.         return io_getchar();
  280.     }
  281.  
  282.     /* Did the read operation result in an end of file */
  283.     if (io_infstack[io_infsp] -> cc == 0 && errno != EWOULDBLOCK) {
  284.  
  285.         /* Set back the file mode to synchronous and close the file */
  286.         if (nonblocking) {
  287.         (VOID) fcntl(io_infstack[io_infsp] -> fd, F_SETFL, 0);
  288.         spush(foreground, TASK);
  289.         doresume();
  290.         tp -> status = RUNNING;
  291.         }
  292.         (VOID) close(io_infstack[io_infsp--] -> fd); 
  293.         
  294.         /* Check if end of input source */
  295.         if (io_eof()) return IO_EOF;
  296.  
  297.         /* Get character from previous file buffer */
  298.         return io_getchar();
  299.     }
  300.  
  301.     /* Run forth level tasks while waiting for input */
  302.     if (tp == foreground) dodetach(); else doinner();
  303.     
  304.     /* Check if the task for empty, i.e., only the foreground */
  305.     if (tp == foreground && tp == ((TASK) tp -> queue.succ)) {
  306.         (VOID) fcntl(io_infstack[io_infsp] -> fd, F_SETFL, 0); 
  307.         nonblocking = FALSE;
  308.     }
  309.     
  310.     /* Allow user extension of the io wait loop */
  311.     io_dispatch();
  312.     }
  313. }
  314.  
  315. VOID io_skip(skpchr)
  316.     CHAR skpchr;        /* Skip character */
  317. {
  318.     CHAR c;
  319.  
  320.     /* Skip all characters until skip termination character or end of file */
  321.     while (io_not_eof()) {
  322.     c = io_getchar();
  323.     if (c == '\n') io_newline();
  324.     if (c == skpchr) return;
  325.     }
  326. }
  327.  
  328. VOID io_scan(buf, brkchr)
  329.     CSTR buf;            /* Pointer to scan buffer */
  330.     CHAR brkchr;        /* Break character */
  331. {
  332.     CHAR c;
  333.     
  334.     /* Initiate buffer as null string */
  335.     *buf = '\0';
  336.  
  337.     /* Check for scanning until white space or special break character */
  338.     if (brkchr == ' ') {
  339.  
  340.     /* While not white space or end of file */
  341.     while (io_not_eof()) {
  342.         c = io_getchar();
  343.         if (c == '\n') io_newline();
  344.         if (ISSPACE(c)) break;
  345.         *buf++ = c;
  346.     }
  347.     }
  348.     else {
  349.  
  350.     /* While not the break character or end of file */
  351.     while (io_not_eof()) {
  352.         c = io_getchar();
  353.         if (c == '\n') io_newline();
  354.         if (c == brkchr) break;
  355.         *buf++ = c;
  356.     }
  357.     }
  358.     
  359.     /* End the string and return */
  360.     *buf = '\0';
  361.     return;
  362. }
  363.  
  364. VOID io_skipspace()
  365. {
  366.     CHAR c;
  367.     
  368.     /* Skip all white spaces */
  369.     while (io_not_eof()) {
  370.     c = io_getchar();
  371.     if (c == '\n') io_newline();
  372.     if (!ISSPACE(c)) break;
  373.     }
  374.     
  375.     /* Step back the buffer pointer */
  376.     if (io_not_eof()) io_infstack[io_infsp] -> bufp -= 1;
  377. }
  378.  
  379. VOID io_initiate(banner)
  380.     CSTR banner;        /* Initiate application message */
  381. {
  382.     INT i;
  383.  
  384.     /* Assign output and error file */
  385.     io_outf = stdout;
  386.     io_errf = stderr;
  387.  
  388.     /* Print banner and add initial paths */
  389.     (VOID) printf(banner);
  390.     (VOID) io_path("TILE:lib", IO_PATH_LAST);
  391.     (VOID) io_path("TILE:", IO_PATH_LAST);
  392.     (VOID) io_path("TILE:tst", IO_PATH_LAST);
  393.     (VOID) io_path("\"\"", IO_PATH_LAST);
  394.  
  395.  
  396.     /* Allocate file buffers */
  397.     for (i = 0; i < INFSTACKSIZE; i++) {
  398.     io_infstack[i] = (INFILE_BUFFER) malloc((unsigned) sizeof(file_buffer));
  399.     if (io_infstack[i] == NIL) {
  400.         (VOID) fprintf(io_errf, "io: cannot allocate file buffers\n");
  401.         exit(0);
  402.     }
  403.     }
  404.  
  405. }    
  406.     
  407. VOID io_finish()
  408. {
  409.     /* Flush any waiting output */
  410.     (VOID) fflush(stdout);    
  411.  
  412.     /* Close all open files */
  413.     while (io_not_eof()) (VOID) close(io_infstack[io_infsp--] -> fd);
  414. }
  415.  
  416.